import random
import pickle
import tkSimpleDialog as tks
import tkFileDialog as tkf
import tkMessageBox as tkm
import random
from batiment import *
from Etoile import *
from TechTree import *
from Planete import *
from unite import *
from univers import *
from CONSTANTESUNITES import *

class Modele(object):
    def __init__(self, parent):
        self.parent=parent
        self.univers=Univers([]) ##Empeche le timerControle de tomber sur des variables manquantes
        self.tech = Technologie('Fer', self)
    

    ##cree un univers avec les parametres par defaut
    ##puis renvoie l'univers au controleur
    def creerDefaut(self, nbEtoiles, largeur, hauteur, profondeur):
        listeEtoiles=[]
        numero = 0
        for i in range(nbEtoiles):
            check=1
            x=random.randint(-largeur,largeur)
            y=random.randint(-hauteur,hauteur)
            z=random.randint(1,(2*profondeur))
            for j in listeEtoiles:
                if j.x==x and j.y==y and j.z==z:
                    check=0
            if check == 0:
                check=1
            else:
                listeEtoiles.append(Etoile(x,y,z,numero,""))
                numero+=1
 
        univers = Univers(listeEtoiles)
        
        return univers
    
    def verifierRessources(self, aConstruire, type, indexEtoile):
        etoile = self.univers.tabEtoiles[indexEtoile]
        if aConstruire == "unite":
            coutMinerai = CONSTANTESUNITES.unites[type]['minerai']
            coutGaz = CONSTANTESUNITES.unites[type]['gaz']
            coutGold = CONSTANTESUNITES.unites[type]['cout']
        elif aConstruire == "structure":
            coutMinerai = CONSTANTESBATIMENTS.structures[type]['minerai']
            coutGaz = CONSTANTESBATIMENTS.structures[type]['gaz']
            coutGold = CONSTANTESBATIMENTS.structures[type]['cout']
        elif aConstruire == "batiment":
            coutMinerai = CONSTANTESBATIMENTS.batiments[type]['coutMinerai']
            coutGaz = CONSTANTESBATIMENTS.batiments[type]['coutGaz']
            coutGold = CONSTANTESBATIMENTS.batiments[type]['coutGold']
        elif aConstruire == "technologie":
            coutMinerai=0
            coutGaz=0
            coutGold=5000
            
        if  self.joueur.gold >= coutGold and etoile.gaz >= coutGaz and etoile.minerai >= coutMinerai:
            self.joueur.gold -= coutGold
            etoile.minerai -= coutMinerai
            etoile.gaz -= coutGaz
            return True
        else:
            return False

    
    def verifierRessource(self,structure,type):
        self.findeliste=0
        for i in self.univers.tabUnites:
            self.findeliste=self.findeliste+1
        if (structure=="stationSpatiale"):
            if type ==1:
                if(CONSTANTESUNITES.guide['cout']< self.joueur.gold):
                    self.joueur.gold=(self.joueur.gold)-(CONSTANTESUNITES.guide['cout'])
                    return True
                else:
                    return False
            else:
                if type ==2:
                    if (CONSTANTESBATIMENTS.structures['stationSpatiale']['cout']<self.joueur.gold):
                        return True
                    else:
                        return False
                else:
                    if (500 < self.joueur.gold):
                        return True
                    else:
                        return False
        if (structure=="centreEchange"):
            if type ==1:
                if(CONSTANTESUNITES.guide['cout']< self.joueur.gold):
                    self.joueur.gold=(self.joueur.gold)-(CONSTANTESUNITES.scout['cout'])
                    return True
                else:
                    return False
            else:
                if type ==2:
                    if (CONSTANTESBATIMENTS.structures['centreEchange']['cout']<self.joueur.gold):
                        return True
                    else:
                        return False
                else:
                    if(500<self.joueur.gold):
                        return True
                    else: 
                        return False        
        if (structure=="centreSciences"):
            if type == 1:
                    return False
            else:
                if type == 2:
                    if (CONSTANTESBATIMENTS.structures['centreSciences']['cout']<self.joueur.gold):
                        return True
                    else:
                        return False
                else:
                    if(500<self.joueur.gold):
                        return True
                    else: 
                        return False
        if (structure=="centreMilitaire"):
            if type == 1:
                    return False
            else:
                if type ==2:
                    if (CONSTANTESBATIMENTS.structures['centreMilitaire']['cout']<self.joueur.gold):
                        return True
                    else:
                        return False
                else:
                    if(500<self.joueur.gold):
                        return True
                    else: 
                        return False              
        if (structure=="usineAttaque"):
            if type ==1:
                if(CONSTANTESUNITES.rapide['cout']< self.joueur.gold):
                    self.joueur.gold=(self.joueur.gold)-(CONSTANTESUNITES.rapide['cout'])
                    return True
                else:
                    return False
            else:
                if (CONSTANTESBATIMENTS.structures['usineAttaque']['cout']<self.joueur.gold):
                    return True
                else:
                    return False
        if (structure=="usineDefense"):
            if type == 1:
                if(CONSTANTESUNITES.lent['cout']< self.joueur.gold):
                    self.joueur.gold=(self.joueur.gold)-(CONSTANTESUNITES.lent['cout'])
                    return True
                else:
                    return False
            else:
                if (CONSTANTESBATIMENTS.structures['usineDefense']['cout']<self.joueur.gold):
                    return True
                else:
                    return False
        if structure == 'extracteurSpatial':
            if type == 1:
                return False
            else:
                if CONSTANTESBATIMENTS.structures['extracteurSpatial']['cout']<self.joueur.gold:
                    return True
                else:
                    return False
                
    def requis (self,etoile):
        if self.univers.tabEtoiles[etoile].populationMax >= self.univers.tabEtoiles[etoile].population + 100:
            return True
        else:
            return False
        
    def dejaConstruit(self,structure,etoile):
        for i in self.univers.tabEtoiles[etoile].tabStructures:
            if i.type == structure:
                return False
        self.joueur.gold= self.joueur.gold-CONSTANTESBATIMENTS.structures[structure]['cout']    
        return True
                 
    def augmentePoint(self,structure):
        self.joueur.gold-=5000
        if structure =='centreMilitaire':
            self.joueur.pMilitaire+=1
            return 'Militaire'
        else:
            if structure =='centreSciences':
                self.joueur.pScience+=1
                return 'Science'
            else:
                if structure=='centreEchange':
                    self.joueur.pEchange+=1
                    return 'Echange'
                
    def augmenterPopulation(self,etoile):
        pass
                
    def changerPopulation(self):
        for uneEtoile in self.univers.tabEtoiles:
            if uneEtoile.nourriture > uneEtoile.population and uneEtoile.population < uneEtoile.populationMax:
                uneEtoile.population += 1
            elif uneEtoile.nourriture < uneEtoile.population:
                uneEtoile.population -= 50
        
    def augmenterArgent(self):
        augmentation=0
        for i in self.univers.tabEtoiles:
            augmentation = augmentation+i.population/20
        self.joueur.gold +=augmentation 
        self.joueur.augmentationargent=augmentation

    def ticBatiments(self):
        for uneEtoile in self.univers.tabEtoiles:
            uneEtoile.accumulerRessources()
                
    def construireStructure(self,structure,etoile):
        nouvelleStructure=Structure(structure,self.univers.tabEtoiles[int(etoile)])
        self.univers.tabEtoiles[int(etoile)].tabStructures.append(nouvelleStructure)
        
    def creerUnite(self, indexEtoile, typeUnite):
        nouvelleUnite = Unite(typeUnite, self.univers.tabEtoiles[indexEtoile])
        self.univers.tabUnites.append(nouvelleUnite)
    
    ##ajoute l'univers et l'entite Joueur() du joueur au modele
    def joindrePartie(self, univers, joueur):
        self.univers=univers
        self.joueur=joueur
    
    ##Demander a l'unite d'initialiser le deplacement puis
    ##l'ajouter l'unite au tableau des unites en mouvement    
    def initMouvement(self, indexUnite,x,y,z):
        self.univers.tabUnites[indexUnite].initMouvement(x,y,z)
        if indexUnite not in self.univers.unitesEnMouvement:
            self.univers.unitesEnMouvement.append(indexUnite)
        
    def cancelAttaque(self,index):
        if index in self.univers.unitesEnCombat:
            del self.univers.unitesEnCombat[index]
            
    def changerTextChat(self, chat, joueur):
        self.parent.changerTextChat(chat, joueur)
    
    def initAttaque(self,indexUniteAttaque,indexUniteDefense):
        #donne une cible a l'attaquan s'il en a aucune et change l'unite de l'attaquant s'il en avait deja une.
        self.univers.unitesEnCombat[indexUniteAttaque]=indexUniteDefense
        
    def shieldDisrupt(self, indexUniteDefense):
        self.univers.tabUnites[indexUniteDefense].shields = 0
        
    def initReparer(self,indexUniteReparateur, indexUniteReparer):
        self.univers.unitesEnReparation[indexUniteReparateur]=indexUniteReparer
        
    def shieldDisruptDistance(self, attaquant, defenseur):
        distanceattaque=math.sqrt(math.pow(abs((self.univers.tabUnites[attaquant].x-self.univers.tabUnites[defenseur].x)),2)+math.pow(abs((self.univers.tabUnites[attaquant].y-self.univers.tabUnites[defenseur].y)),2)+math.pow(abs((self.univers.tabUnites[attaquant].z-self.univers.tabUnites[defenseur].z)),2))
        if distanceattaque <= self.univers.tabUnites[attaquant].range:
            print "ok"
            return "ok"
        else:
            print "fail"
            return "fail"
    
    def attaquer(self):
        supprimer=0
        sortir=0
        uniteAEnlever=[]
        for i in self.univers.unitesEnCombat:
            attaquant=i
            defenseur=self.univers.unitesEnCombat[i]
            if self.univers.tabUnites[attaquant].statut=="mort":
                uniteAEnlever.append(attaquant)
                sortir=1
            
            #si la distance est suffisante la vie de la cible est reduite
                                          
            distanceattaque=math.sqrt(math.pow(abs((self.univers.tabUnites[attaquant].x-self.univers.tabUnites[defenseur].x)),2)+math.pow(abs((self.univers.tabUnites[attaquant].y-self.univers.tabUnites[defenseur].y)),2)+math.pow(abs((self.univers.tabUnites[attaquant].z-self.univers.tabUnites[defenseur].z)),2))
            
            if distanceattaque <= self.univers.tabUnites[attaquant].range and sortir==0: 
                #arrete le mouvement s'il y en a un
                if attaquant in self.univers.unitesEnMouvement:
                    self.univers.unitesEnMouvement.remove(attaquant)
                    
                if self.univers.tabUnites[defenseur].shields>0:
                    self.univers.tabUnites[defenseur].shields-=self.univers.tabUnites[attaquant].attaque
                    if self.univers.tabUnites[defenseur].shields<0:
                        #on additionne le shields au hp car les shields sont negatifs, puis on les soustraits
                        self.univers.tabUnites[defenseur].hp+=self.univers.tabUnites[defenseur].shields  
                        self.univers.tabUnites[defenseur].shields=0
                else:
                    self.univers.tabUnites[defenseur].hp-=self.univers.tabUnites[attaquant].attaque
                    if self.univers.tabUnites[defenseur].hp<0:
                        self.univers.tabUnites[defenseur].hp=0
                        self.univers.tabUnites[defenseur].statut="mort"
                        #print "bob"
                        #print len(self.univers.tabUnites)
                        uniteAEnlever.append(attaquant)
            # si la distance n'est pas suffisante, alors initier un mouvement jusqu'elle le soit
            else:
                self.initMouvement(attaquant,self.univers.tabUnites[defenseur].x,self.univers.tabUnites[defenseur].y,self.univers.tabUnites[defenseur].z)
        
        for i in uniteAEnlever:
            del self.univers.unitesEnCombat[i]
        
                                
    def reparer(self):
        supprimer = 0
        for i in self.univers.unitesEnReparation:
            reparateur=i
            aReparer=self.univers.unitesEnReparation[i]
            
            distanceattaque=math.sqrt(math.pow(abs((self.univers.tabUnites[reparateur].x-self.univers.tabUnites[aReparer].x)),2)+math.pow(abs((self.univers.tabUnites[reparateur].y-self.univers.tabUnites[aReparer].y)),2)+math.pow(abs((self.univers.tabUnites[reparateur].z-self.univers.tabUnites[aReparer].z)),2))
            if distanceattaque <= self.univers.tabUnites[reparateur].range: 
                #arrete le mouvement s'il y en a un
                if reparateur in self.univers.unitesEnMouvement:
                    self.univers.unitesEnMouvement.remove(reparateur)
                
                if self.univers.tabUnites[aReparer].hp>0 and self.univers.tabUnites[aReparer].hp<CONSTANTESUNITES.unites[self.univers.tabUnites[aReparer].type]['hp']-20:
                    self.univers.tabUnites[aReparer].hp+=20
                elif self.univers.tabUnites[aReparer].hp>=CONSTANTESUNITES.unites[self.univers.tabUnites[aReparer].type]['hp']-20 and self.univers.tabUnites[aReparer].hp<CONSTANTESUNITES.unites[self.univers.tabUnites[aReparer].type]['hp']:
                    self.univers.tabUnites[aReparer].hp = CONSTANTESUNITES.unites[self.univers.tabUnites[aReparer].type]['hp']
                    supprimer = 1
                else:
                    supprimer = 1
            else:
                self.initMouvement(reparateur,self.univers.tabUnites[aReparer].x,self.univers.tabUnites[aReparer].y,self.univers.tabUnites[aReparer].z)
                
        if supprimer==1:
            del self.univers.unitesEnReparation[reparateur]
            
    ##Passer a travers de la liste des unites en mouvement
    ##et leur demander de se deplacer
    def bougerUnites(self):
        for i in self.univers.unitesEnMouvement:
            reponse = self.univers.tabUnites[i].bouger()
            if reponse == "fini":
                self.univers.unitesEnMouvement.remove(i)
        
    def checkProprietaire(self, indexUnite):
        if self.univers.tabUnites[indexUnite].proprietaire == self.joueur.nom:
            return 1
        else:
            return 0
    def approprierEtoile(self, nick,index):
        self.univers.tabEtoiles[index].proprietaire=nick
        
    def checkDistance(self, type, cible, unite):
        ##assurance de qualite...
        cible = int(cible)
        unite = int(unite)
        ######################
        if type == "etoile":
            distance = math.sqrt(math.pow(abs((self.univers.tabUnites[unite].x-self.univers.tabEtoiles[cible].x)),2)+math.pow(abs((self.univers.tabUnites[unite].y-self.univers.tabEtoiles[cible].y)),2)+math.pow(abs((self.univers.tabUnites[unite].z-self.univers.tabEtoiles[cible].z)),2))
        elif type == "unite":
            distance = math.sqrt(math.pow(abs((self.univers.tabUnites[unite].x-self.univers.tabUnites[cible].x)),2)+math.pow(abs((self.univers.tabUnites[unite].y-self.univers.tabUnites[cible].y)),2)+math.pow(abs((self.univers.tabUnites[unite].z-self.univers.tabUnites[cible].z)),2))
        if distance < self.univers.tabUnites[unite].range:
            return True
        else:
            return False

    #check sur soi pour voir si la du joueur est inferieur a sa vie avant le ping
    def riposte(self):
                
        indexUnite=0
        for unite in self.univers.tabUnites:
            if indexUnite in self.univers.unitesEnCombat:
                pass
            elif indexUnite in self.univers.unitesEnMouvement:
                pass
            elif unite.hp < unite.hpPrePing or unite.shields < unite.shieldsPrePing:
                for uniteAttaquante in list(self.univers.unitesEnCombat):
                    if self.univers.unitesEnCombat[uniteAttaquante]==indexUnite:
                        self.initAttaque(indexUnite, uniteAttaquante)
            indexUnite=indexUnite+1
    
    
    def checkProprietaireEtoile(self, indexEtoile):
        if self.univers.tabEtoiles[indexEtoile].proprietaire == self.joueur.nom:
            return 1
        else:
            return 0
    
    ##Ajoute un joueur a la partie
    def nouveauJoueur(self, newJoueur, newEtoile, newUnite):
        self.univers.listeJoueurs.append(newJoueur)
        self.univers.tabEtoiles[newEtoile.numero]=newEtoile
        self.univers.tabUnites.append(newUnite)
        
    ##Creer un Batiment
    def creerBatiment(self, planeteSelectionnee, etoileSelectionnee, typeBatiment):
        unePlanete=self.univers.tabEtoiles[etoileSelectionnee].tabPlanetes[planeteSelectionnee]
        message=self.estPossibleDeConstruireBatiment(unePlanete,typeBatiment)
        if message=="OK":           
            self.joueur.gold-=CONSTANTESBATIMENTS.batiments[typeBatiment]['coutGold']
            unePlanete.etoile.gaz-=CONSTANTESBATIMENTS.batiments[typeBatiment]['coutGaz']
            unePlanete.etoile.minerai-=CONSTANTESBATIMENTS.batiments[typeBatiment]['coutMinerai']
            unePlanete.etoile.nourriture-=CONSTANTESBATIMENTS.batiments[typeBatiment]['coutNourriture']
            
            #si ferme, augmente directement la nourriture de l'etoile
            if typeBatiment=='agricultureFerme':
                self.univers.tabEtoiles[etoileSelectionnee].nourriture=self.univers.tabEtoiles[etoileSelectionnee].nourriture+100
            
            unBatiment=Batiment(typeBatiment,unePlanete)
            unePlanete.batiments.append(unBatiment)
            message= "Batiment en construction: "+typeBatiment
        return message
 
 
#         self.nourriture=0
#        self.minerai=0
#        self.population=0
#        self.gaz=0           
    #Verifier les conditions de construction de batiments et retourne un message en concequence
    #Procede par elimination
    def estPossibleDeConstruireBatiment(self,unePlanete,typeBatiment):   
        #si non $
        if(self.joueur.gold<CONSTANTESBATIMENTS.batiments[typeBatiment]['coutGold']):
            return "Construction impossible: Argent insuffisant"
        #si non gaz
        elif (unePlanete.etoile.gaz<CONSTANTESBATIMENTS.batiments[typeBatiment]['coutGaz']):
            return "Construction impossible: Gaz insuffisant"
        #si non minerai
        elif (unePlanete.etoile.minerai<CONSTANTESBATIMENTS.batiments[typeBatiment]['coutMinerai']):
            return "Construction impossible: Minerai insuffisant"      
        #si non nourriture
        elif (unePlanete.etoile.nourriture<CONSTANTESBATIMENTS.batiments[typeBatiment]['coutNourriture']):
            return "Construction impossible: Nourriture insuffisante"
        #si limite depasse
        elif self.limiteBatimentEstDepasse(unePlanete,typeBatiment):
            return "Construction impossible: Limite de construction depasse"    
        #si mauvais type de planete
        elif not CONSTANTESBATIMENTS.batiments[typeBatiment][unePlanete.type]:
            return "Construction impossible: Mauvais type de planete"   
        #Sinon OK
        else:
            return "OK"    

    def limiteBatimentEstDepasse(self,unePlanete,typeBatiment):   
        #Si deja un hopital limite depasse
        if typeBatiment=="hopital":
            for unBatiment in unePlanete.batiments:
                if unBatiment.type==typeBatiment:
                    return True
            #Pas d'hopital limite non depasse    
            return False
        #Si deja un recycleur limite depasse
        elif typeBatiment=="recycleur":
            for unBatiment in unePlanete.batiments:
                if unBatiment.type==typeBatiment:
                    return True
            #pas de recycleur donc non depasse
            return False
        #Si deja un bouclier alors  limite depasse
        elif typeBatiment=="bouclier":
            for unBatiment in unePlanete.batiments:
                if unBatiment.type==typeBatiment:
                    return True
            #pas de bouclier donc limite non depasse    
            return False
        #Si une ferme
        elif typeBatiment=="ferme":
            nombreFermes=0
            #Loop pour compter les fermes
            for unBatiment in unePlanete.batiments:
                if unBatiment.type==typeBatiment:
                    nombreFermes+=1  
            #Si nombre de fermes > que % arbitraire
            if  nombreFermes>self.population/10:# A ajuster plus tard
                return True
            #Limite non depasse
            else:
                return False
        #Les autres batiments n'ont pas de limite
        else:
            return False
            

               
#    def deplacerUnite(self, x, y, unite):
#        #if self.joueur == unite.proprietaire:
#        self.parent.initMouvement(0, x, y, 1)